﻿using System;

namespace paiban
{
    using paiban.data;

    public class DasaoCalc // 打扫人员计算
    {
        internal WorkPersonInfo info;
        internal bool avg_mode { get; set; }
        internal DasaoTable table { get; set; }
        internal DasaoTableThumb thumb { get; set; }
        internal List<string> testedlist;
        internal int person_min_do;
        internal int person_max_do;
        internal string[] premonth_maxperson;
        internal bool success = false;
        public DasaoCalc(WorkPersonInfo workperson)
        {
            testedlist = new List<string>();
            this.info = workperson;
            premonth_maxperson = cgsys.config.Array("上月多打扫人员");
            avg_mode = cgsys.config.YesOrNo("平均化模式");
            table = new DasaoTable(workperson);
            thumb = new DasaoTableThumb(table);

            if (avg_mode)
            {
                person_min_do = person_max_do = table.daosao_table_size / table.dasao_person_count;
                if (table.daosao_table_size % table.dasao_person_count != 0) person_max_do++;
            }

            init_data();
        }
        internal void init_data()
        {
            foreach (var day in info.LoopDays())
            {
                table.Goto(day);
                table.Entry(table.ReadDasaoPerson().GetEnumerator());
            }

            remember_now();
            Check();
        }
        internal void Calc01()
        {

            var hash = string.Empty;
            while (true)
            {
                CALC_01_BEGIN:
                foreach (var day in info.LoopDays())
                {
                    table.Goto(day);
                    foreach (var person in table.Read())
                    {
                        if(thumb.ReadPersonCount(person) > person_min_do)
                        {
                            foreach (var newperson in table.ReadDasaoPerson())
                            {
                                if (table.IsIn(newperson)) continue;

                                if (thumb.ReadPersonCount(newperson)<person_min_do)
                                {
                                    table.Change(person, newperson);

                                    if (is_remembered())
                                    {
                                        table.Change(newperson, person);
                                        continue;
                                    }

                                    remember_now();
                                    if (Check()) return;
                                    goto CALC_01_BEGIN;
                                }
                            }
                        }
                    }

                }

                if (hash == table.CalcHash()) break;
                hash = table.CalcHash();
            }
        }

        internal void Calc02()
        {

            var hash = string.Empty;
            while (true)
            {
            CALC_02_BEGIN:
                foreach (var day in info.LoopDays())
                {
                    table.Goto(day);
                    foreach (var person in table.Read())
                    {
                        if (thumb.ReadPersonCount(person) > person_max_do)
                        {
                            foreach (var newperson in table.ReadDasaoPerson())
                            {
                                if (table.IsIn(newperson)) continue;

                                if (thumb.ReadPersonCount(newperson) < person_max_do)
                                {
                                    table.Change(person, newperson);

                                    if (is_remembered())
                                    {
                                        table.Change(newperson, person);
                                        continue;
                                    }

                                    remember_now();
                                    if (Check()) return;
                                    goto CALC_02_BEGIN;
                                }
                            }
                        }
                    }

                }

                if (hash == table.CalcHash()) break;
                hash = table.CalcHash();
            }
        }

        internal void Calc03()
        {

            var hash = string.Empty;
            while (true)
            {
            CALC_03_BEGIN:
                foreach (var day in info.LoopDays())
                {
                    table.Goto(day);
                    foreach (var person in table.Read())
                    {
                        if (premonth_maxperson.Contains(person) && thumb.ReadPersonCount(person) > person_min_do)
                        {
                            foreach (var newperson in table.ReadDasaoPerson(day))
                            {
                                if (premonth_maxperson.Contains(newperson)) continue;
                                if (table.IsIn(newperson)) continue;

                                if (thumb.ReadPersonCount(newperson) < person_max_do)
                                {
                                    table.Change(person, newperson);

                                    if (is_remembered())
                                    {
                                        table.Change(newperson, person);
                                        continue;
                                    }

                                    remember_now();
                                    if (Check()) return;
                                    goto CALC_03_BEGIN;
                                }
                            }
                        }
                    }

                }

                if (hash == table.CalcHash()) break;
                hash = table.CalcHash();
            }
        }

        public void Calc()
        {
            var offset = 0;
            while (!success)
            {
                if (!success) Calc01();
                if (!success) Calc03();
                if (!success) Calc02();
                if (!success) Calc03();

                offset++;
                if (offset < info.person_count) break;
                if (!success) table.info.MoveBanbiao();
                if (!success) init_data();
            }
            
            Console.WriteLine($"dasao: {success}");
        }

        public bool Check()
        {
            for(var i = 0; i < thumb.thumb_sum_count; i++)
            {
                if (table.no_dasao_person.Contains(thumb.personmap[i])) continue;
                if (thumb.thumb_sum[i] < person_min_do || thumb.thumb_sum[i] > person_max_do) return false;
            }

            for(var i = 0; i < premonth_maxperson.Length; i++)
            {
                if (table.no_dasao_person.Contains(thumb.personmap[i])) continue;
                if (thumb.ReadPersonCount(premonth_maxperson[i]) > person_min_do) return false;
            }

            this.success = true;
            return true;
        }
        internal void remember_now()
        {
            testedlist.Add(table.CalcHash());
            thumb.Update();
        }
        internal bool is_remembered()
        {
            return testedlist.Contains(table.CalcHash());
        }
    }
}
